<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta
    name="viewport"
    content="width=device-width, initial-scale=1.0"
  >
  <title>Virtual List</title>
  <style>
    #container {
      height: 300px;
      width: 300px;
      overflow-y: auto;
      position: relative;
      border: 1px solid #ccc;
    }

    .item {
      height: 50px;
      width: 100%;
      box-sizing: border-box;
      border-bottom: 1px solid #eee;
      padding: 5px;
    }

    .spacer {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
    }

    .loading {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100%;
      font-size: 20px;
    }
  </style>
</head>

<body>
  <div id="container">
    <div id="list"></div>
    <div id="spacer"></div>
  </div>
  <div
    id="loading"
    class="loading"
  >Loading...</div>

  <script>
    const totalItems = 10000;   // 数据总量
    const itemHeight = 50;      // 每个列表项的高度
    const containerHeight = 300; // 容器的高度
    const visibleCount = Math.ceil(containerHeight / itemHeight);  // 计算可见项目数

    const container = document.getElementById('container');
    const list = document.getElementById('list');
    const spacer = document.getElementById('spacer');
    const loading = document.getElementById('loading');

    // 假设数据已经生成
    const data = Array.from({ length: totalItems }, (_, i) => `Item ${i + 1}`);

    spacer.style.height = `${(totalItems - 6) * itemHeight}px`;  // 设置占位元素的高度

    function renderVisibleItems() {
      console.log('renderVisibleItems')
      const scrollTop = container.scrollTop;  // 获取滚动位置
      const startIndex = Math.floor(scrollTop / itemHeight); // 当前视口内第一个可见元素的索引
      const endIndex = Math.min(startIndex + visibleCount + 1, totalItems); // 视口内最后一个可见元素的索引

      list.style.transform = `translateY(${startIndex * itemHeight}px)`; // 设置列表的偏移
      list.innerHTML = '';  // 清空列表

      // 渲染可见的项目
      for (let i = startIndex; i < endIndex; i++) {
        const item = document.createElement('div');
        item.className = 'item';
        item.textContent = data[i];
        list.appendChild(item);
      }
    }

    // 初始渲染
    loading.style.display = 'block';  // 显示加载指示器
    setTimeout(() => {
      renderVisibleItems();
      loading.style.display = 'none';  // 隐藏加载指示器
    }, 1000);  // 假设数据加载需要1秒钟

    // 节流监听滚动事件
    container.addEventListener('scroll', renderVisibleItems);
    function throttle(func, delay) {
      let timer = null
      return function () {
        if (timer) return
        timer = setTimeout(() => {
          func.apply(this, arguments)
          timer = null
        }, 100);
      }
    }
  </script>
</body>

</html>